package com.gl.saasservice.sys.service;

import com.alibaba.fastjson.JSON;
import com.gl.common.util.StringUtils;
import com.gl.common.vo.ApiData;
import com.gl.framework.web.response.Result;
import com.gl.saasservice.entity.Role;
import com.gl.saasservice.entity.RolePermission;
import com.gl.saasservice.entity.UserRole;
import com.gl.saasservice.sys.mapper.PermissionRowMapper;
import com.gl.saasservice.repository.DepartmentRepository;
import com.gl.saasservice.repository.RolePermissionRepository;
import com.gl.saasservice.repository.RoleRepository;
import com.gl.saasservice.repository.UserRoleRepository;
import com.gl.saasservice.sys.utils.CheckUtil;
import com.gl.saasservice.sys.vo.PermissionVO;
import com.gl.saasservice.sys.vo.RoleVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class RoleService {
    private static final Logger LOG = LoggerFactory.getLogger(RoleService.class);

    @Autowired
    private RoleRepository roleRepository;
    @Autowired
    private RolePermissionRepository rolePermissionRepository;
    @Autowired
    private UserRoleRepository userRoleRepository;
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired
    private DepartmentRepository departmentRepository;

    public final static String APP_REGISTERED_ROLE_CODE = "APP-COMMON-ROLE";//APP注册用户默认角色CODE

    public final static String APP_COMMON_ROLE_DEPT = "APP-COMMON-ROLE-DEPT";//APP-单位承租人角色

    public final static String APP_COMMON_ROLE_ONE = "APP-COMMON-ROLE_ONE";// APP-个人承租人角色

    public Result pages(String accessToken, Integer pageNumber, Integer pageSize, RoleVO vo, String flag) {
        LOG.info("---RoleService pages accessToken={},pageNumber={}, pageSize={}, roleVO={}", accessToken, pageNumber, pageSize);

        String SQL = " select r.*,d.name AS orgName from saas_role r  LEFT JOIN saas_department d ON r.org_id=d.id  ";

        String count = "select count(1) from saas_role r LEFT JOIN saas_department d ON r.org_id=d.id  ";

        String offsets = " limit ? offset ?";

        StringBuilder where = new StringBuilder("WHERE 1 = 1 \n");
        List<Object> args = new ArrayList<>();


        if (flag.equals("app")) {
            where.append(" AND r.nature_type = 1 \n");
            where.append(" AND r.org_id = -1 \n");
        } else {
            where.append(" AND r.org_id != -1 \n");
        }


        if (vo != null) {
            if (StringUtils.isNotBlank(vo.getName())) {
                where.append(" AND r.name like ? \n");
                args.add("%" + vo.getName() + "%");
            }
            if (StringUtils.isNotBlank(vo.getCode())) {
                where.append(" AND r.code like ? \n");
                args.add("%" + vo.getCode() + "%");
            }
            if (StringUtils.isNotBlank(vo.getDescription())) {
                where.append(" AND r.description like ? \n");
                args.add("%" + vo.getDescription() + "%");
            }
            //公司名称
            if (StringUtils.isNotBlank(vo.getOrgName())) {
                where.append(" AND d.name like ? \n");
                args.add("%" + vo.getOrgName() + "%");
            }

        }

        ApiData<RoleVO> apiData = new ApiData<>();

        Long total = jdbcTemplate.queryForObject(count + where, Long.class, args.toArray());
        if (total == 0) {
            return Result.success(apiData);
        }

        // 查询分页数据
        where.append(" ORDER BY ").append(" r.id desc ").append(" \n").append(offsets);
        args.add(pageSize);
        args.add(pageNumber * pageSize);
        List<RoleVO> data = jdbcTemplate.query(SQL + where, new BeanPropertyRowMapper<>(RoleVO.class), args.toArray());

        List<Long> parentIdList = data.stream().map(RoleVO::getParentId).collect(Collectors.toList());
        List<Role> parentRoleList = roleRepository.findByIdIn(parentIdList);

        for (RoleVO roleVO : data) {
            for (Role parent : parentRoleList) {
                if (roleVO.getParentId().equals(parent.getId())) {
                    roleVO.setShowName(parent.getName() + " -> " + roleVO.getName());
                } else {
                    roleVO.setShowName(roleVO.getName());
                }
            }
        }

      /*   List<Long> orgIds=data.stream().map(RoleVO::getOrgId).collect(Collectors.toList());

        List<Department> department = departmentRepository.findByIdIn(orgIds);

        for(RoleVO roleVO : data){
            for(Department d :department) {
                if (roleVO.getOrgId().equals(d.getId())) {
                    roleVO.setOrgName(d.getName());
                }
            }
        }*/

        apiData.setTotal(total);
        apiData.setData(data);

        return Result.success(apiData);
    }

    public Result save(String accessToken, RoleVO roleVO) {
        LOG.info("---RoleService save accessToken={},roleVO={}", accessToken, JSON.toJSONString(roleVO));

        CheckUtil checkUtil = new CheckUtil();
        checkUtil.checkValues(roleVO);
        if (checkUtil.isNull()) {
            return Result.fail(checkUtil.getMessage());
        }

        Role role = new Role();
        BeanUtils.copyProperties(roleVO, role);

        if (roleVO.getId() == null) {
            Role entity = roleRepository.findByName(roleVO.getName());
            if (entity != null) {
                return Result.fail("角色名称已存在");
            }

            Role entity1 = roleRepository.findByCode(roleVO.getCode());
            if (entity1 != null) {
                return Result.fail("角色编码已存在");
            }

            role.setOrgId(-1L);
            role.setParentId(0L);
            role.setProperty(2);
            role.setType(0);
            role.setPropertyType(0);
            role.setNatureType(1);

        } else {
            Role entity = roleRepository.findById(roleVO.getId()).get();

            if (entity.getCode().equals(APP_REGISTERED_ROLE_CODE) || entity.getCode().equals(APP_COMMON_ROLE_DEPT) || entity.getCode().equals(APP_COMMON_ROLE_ONE)) {
                return Result.fail("特定角色编码不能修改");
            }

            if (!entity.getName().equals(roleVO.getName())) {  //更新名称
                Role r = roleRepository.findByName(roleVO.getName());
                if (r != null) {
                    return Result.fail("角色名称已存在");
                }
            }

            if (!roleVO.getCode().equals(entity.getCode())) {  //更新编码
                Role c = roleRepository.findByCode(roleVO.getCode());
                if (c != null) {
                    return Result.fail("角色编码已存在");
                }
            }

        }

        roleRepository.save(role);
        return Result.success(null);
    }

    public Result delete(String accessToken, Long id) {
        LOG.info("---RoleService delete accessToken={},id={}", accessToken, id);

        Optional<Role> optional = roleRepository.findById(id);
        if (!optional.isPresent()) {
            return Result.fail("当前角色数据不存在！");
        }
        List<UserRole> userRoleList = userRoleRepository.findByRoleId(optional.get().getId());

        rolePermissionRepository.deleteByRoleId(id);
        userRoleRepository.deleteByRoleId(id);
        roleRepository.deleteById(id);

/*        //删除用户权限缓存
        for(UserRole userRole : userRoleList) {
        	redisService.delUserPerissionRedis(userRole.getUserId());
        }
        redisService.delPerissionRedis();*/

        return Result.success(null);
    }

    public Result permissionList(String accessToken, Long roleId) {
        LOG.info("---RoleService permissionList accessToken={},roleId={}", accessToken, roleId);

        try {
            StringBuffer sql = new StringBuffer("SELECT id, parent_id, NAME, TYPE, url, method, CODE, sortby, icon,master_show FROM saas_permission ORDER BY parent_id,sortby");
            StringBuffer rolePermSql = new StringBuffer("SELECT permission_id FROM saas_role_app_ref WHERE role_id = ? ORDER BY permission_id");

            List<PermissionVO> list = jdbcTemplate.query(sql.toString(), new PermissionRowMapper());
            List<Map<String, Object>> rolePermList = jdbcTemplate.queryForList(rolePermSql.toString(), roleId);

            if (list == null || list.isEmpty()) {
                return Result.success(null);
            }

       /*     List<LevelVO> levelList = findLevel("fh_sys_permission");
            for (PermissionVO pvo : list) {
                for (LevelVO lvo : levelList) {
                    if (pvo.getId().longValue() == lvo.getId().longValue()) {
                        pvo.setLevel(lvo.getLevel());
                    }
                }
            }*/

            checkSelect(list, rolePermList, "permission_id");

            // 重排结果
            List<PermissionVO> newList = new LinkedList<PermissionVO>();
            sortList(newList, list);

            return Result.success(newList);
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
            return Result.fail();
        }
    }

    /**
     * 排序
     *
     * @param newList
     * @param list
     * @author chensenrong
     */
    private void sortList(List<PermissionVO> newList, List<PermissionVO> list) {
        for (PermissionVO vo : list) {
            if (vo.getParentId().longValue() == 0) {
                newList.add(vo);
                findChild(vo.getId(), newList, list);
            }
        }
    }

    /**
     * 递归找下级
     *
     * @param parentId
     * @param newList
     * @param list
     * @author chensenrong
     */
    private void findChild(Long parentId, List<PermissionVO> newList, List<PermissionVO> list) {
        for (PermissionVO vo : list) {
            if (parentId.longValue() == vo.getParentId().longValue()) {
                newList.add(vo);
                findChild(vo.getId(), newList, list);
            }
        }
    }

    /**
     * 设置已有权限
     *
     * @param list
     * @param rolePermList
     * @param permIdColumn
     * @author chensenrong
     */
    private void checkSelect(List<PermissionVO> list, List<Map<String, Object>> rolePermList, String permIdColumn) {
        for (PermissionVO vo : list) {
            if (hasPerm(vo.getId(), rolePermList, permIdColumn)) {
                vo.setCheck(true);
            } else {
                vo.setCheck(false);
            }
        }
    }

    /**
     * 判断是否拥有权限
     *
     * @param id
     * @param rolePermList
     * @param permIdColumn
     * @return
     * @author chensenrong
     */
    private boolean hasPerm(Long id, List<Map<String, Object>> rolePermList, String permIdColumn) {
        for (Map<String, Object> map : rolePermList) {
            Object perIdObj = map.get(permIdColumn);
            if (perIdObj == null) {
                continue;
            }

            Long perId = Long.valueOf(perIdObj.toString());
            if (id.longValue() == perId.longValue()) {
                return true;
            }
        }

        return false;
    }

  /*  private List<LevelVO> findLevel(String tableName) {
        String sql = "SELECT id AS ID,parent_id ,levels AS 'level', paths AS 'path' FROM ( " + "SELECT id,parent_id, "
                + "@le:= IF (parent_id = 0 ,0,  " + "  IF( LOCATE( CONCAT('|',parent_id,':'),@pathlevel)  > 0 ,   "
                + "      SUBSTRING_INDEX( SUBSTRING_INDEX(@pathlevel,CONCAT('|',parent_id,':'),-1),'|',1) +1 "
                + " ,@le+1) ) levels " + ", @pathlevel:= CONCAT(@pathlevel,'|',id,':', @le ,'|') pathlevel "
                + ", @pathnodes:= IF( parent_id =0,',0',  " + "   CONCAT_WS(',', "
                + "   IF( LOCATE( CONCAT('|',parent_id,':'),@pathall) > 0 ,  "
                + "     SUBSTRING_INDEX( SUBSTRING_INDEX(@pathall,CONCAT('|',parent_id,':'),-1),'|',1) "
                + "    ,@pathnodes ) ,parent_id ) )paths "
                + ",@pathall:=CONCAT(@pathall,'|',id,':', @pathnodes ,'|') pathall  " + "  FROM " + tableName + ",  "
                + "(SELECT @le:=0,@pathlevel:='', @pathall:='',@pathnodes:='') vv " + " ORDER BY parent_id,id "
                + ") src " + "ORDER BY id";

        return jdbcTemplate.query(sql, new LevelRowMapper());
    }*/

    /**
     * 角色授权
     *
     * @param accessToken
     * @param roleId
     * @param permissionIds
     * @author chensenrong
     */
    @Transactional
    public Result saveRolePermission(String accessToken, Long roleId, List<Long> permissionIds) {
        LOG.info("---RoleService saveRolePermission accessToken={},roleId={},permissionIds={}", accessToken, roleId, permissionIds);
        try {
            Optional<Role> optional = roleRepository.findById(roleId);
            if (!optional.isPresent()) {
                return Result.fail("没有找到此角色");
            }
            Role mainRole = optional.get();

            if (permissionIds.isEmpty()) {
                LOG.error("---RoleSevice.saveRolePermission---> 授权的权限为空 , roleId={}, premissionIds = {}", roleId, permissionIds);
                return Result.fail("授权的权限为空");
            } else {
                List<RolePermission> rpList = rolePermissionRepository.findByRoleId(roleId);
                List<Long> rpPermissionIds = rpList.stream().map(RolePermission::getPermissionId).distinct().collect(Collectors.toList());

                //取出已删除权限
                List<Long> differentList = listCompare(rpPermissionIds, permissionIds);
                //机构除主管理员角色，去掉已删除权限
                List<Role> otherRoleList = roleRepository.selectOtherRole(mainRole.getOrgId());
                List<Long> otherRoleIds = otherRoleList.stream().map(Role::getId).distinct().collect(Collectors.toList());
                if (!otherRoleIds.isEmpty() && !differentList.isEmpty()) {
                    rolePermissionRepository.deleteByRoleIdInAndPermissionIdIn(otherRoleIds, differentList);
                }

                //删除主管理员权限
                rolePermissionRepository.deleteAll(rpList);
                //重新授权主管理员权限
                List<RolePermission> list = new ArrayList<>();
                for (Long id : permissionIds) {
                    if (id == null) {
                        continue;
                    }
                    RolePermission entity = new RolePermission();
                    entity.setRoleId(roleId);
                    entity.setPermissionId(id);
                    list.add(entity);
                }
                rolePermissionRepository.saveAll(list);

                return Result.success(null);
            }
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
            return Result.fail();
        }
    }

    public List<Long> listCompare(List<Long> menuOneList, List<Long> resourceList) {
        Map<Long, Integer> map = new HashMap<Long, Integer>(resourceList.size());
        List<Long> differentList = new ArrayList<Long>();
        for (Long resource : resourceList) {
            map.put(resource, 1);
        }
        for (Long resource1 : menuOneList) {
            if (map.get(resource1) == null) {
                differentList.add(resource1);
            }
        }
        return differentList;
    }


}
